﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

///From TheShyGuy
///--this is my class i used for sloped tiles a while ago and i just put it in here 
///--to use for the intersection depth
namespace TileEngine
{
    public enum Flip
    {
        None = 0,
        Horizontal = 1,
        Vertical = 2,
    }
    public class RightTriangle
    {

        public Vector2 Origin;

        Vector2 p90;
        Vector2 p2;
        Vector2 p3;
        /// <summary>
        /// The point tangent to the 90 degree angle
        /// </summary>
        public Vector2 P1_90
        {
            get { return p90 + Origin; }
            set
            {
                p90 = value;
            }
        }
        public Vector2 P2
        {
            get { return p2 + Origin; }
            set { p2 = value; }
        }
        public Vector2 P3
        {
            get { return p3 + Origin; }
            set { p3 = value; }
        }

        public Rectangle Bounds
        {
            get { return new Rectangle((int)Origin.X, (int)Origin.Y, (int)Width, (int)Height); }
        }
        public float Left { get { return Math.Min(P3.X, Math.Min(P1_90.X, P2.X)); } }
        public float Bottom { get { return Math.Max(P3.Y, Math.Max(P1_90.Y, P2.Y)); } }
        public float Right { get { return Math.Max(P3.X, Math.Max(P1_90.X, P2.X)); } }
        public float Top { get { return Math.Min(P3.Y, Math.Min(P1_90.Y, P2.Y)); } }

        public float Width
        {
            get { return Right - Left; }
        }
        public float Height
        {
            get { return Bottom - Top; }
        }

        /// <summary>
        /// 1 = right
        /// -1 = left
        /// </summary>
        public int HorzDirection
        {
            get
            {
                if (P1_90.X < Right)
                    return 1;
                else//X > Left
                    return -1;
            }
        }
        /// <summary>
        /// 1 = upwards
        /// -1 = upsideDown
        /// </summary>
        public int VertDirection
        {
            get
            {
                //inverse?
                if (P1_90.Y > Top)
                    return 1;//1
                else//Y > Bottom
                    return -1;//-1
            }
        }
        public float B
        {
            get
            {
                Vector2 diffV = p3 - p2;
                return P3.Y - Slope * P3.X;
            }//coulda used p3, as long as its a point on the slope,nvm
        }

        public int Direction
        {
            get { return HorzDirection * VertDirection; }
        }
        public float Slope
        {
            //horz | vert
            //1,1 = 1= neg
            //1,-1 = -1 = pos
            //-1,1 = -1 = pos
            //-1,-1 = 1 = neg
            get
            {
                return Height / Width * Direction;
            }
        }


        /// <summary>
        /// Sets the triangles points so that p1 == the point of the 90 degree angle
        /// p2 and p3 are the points adj to the hyp
        /// </summary>
        /// <param name="p_90"></param>
        /// <param name="p2"></param>
        /// <param name="p3"></param>
        public void SetPoints(Vector2 p_90, Vector2 p2, Vector2 p3)
        {
            P1_90 = p_90;
            P2 = p2;
            P3 = p3;
        }
        public void FlipDirection(Flip side)
        {
            List<Vector2> points = new List<Vector2>() { p90, p2, p3 };

            float top = Top - Origin.Y;
            float left = Left - Origin.X;
            float bottom = Bottom - Origin.Y;
            float right = Right - Origin.X;

            Vector2 topLeft = new Vector2(left, top);
            Vector2 topRight = new Vector2(right, top);
            Vector2 bottomLeft = new Vector2(left, bottom);
            Vector2 bottomRight = new Vector2(right, bottom);

            if (side == Flip.Horizontal)
            {
                if (HorzDirection == 1 && VertDirection == -1)
                {
                    p90 = bottomRight;
                    p2 = bottomLeft;
                    p3 = topRight;
                }
                else if (HorzDirection == 1 && VertDirection == 1)
                {
                    p90 = topRight;
                    p2 = topLeft;
                    p3 = bottomRight;
                }
                else if (HorzDirection == -1 && VertDirection == -1)
                {
                    p90 = bottomLeft;
                    p2 = bottomRight;
                    p3 = topLeft;
                }
                else if (HorzDirection == -1 && VertDirection == 1)
                {
                    p90 = topLeft;
                    p2 = topRight;
                    p3 = bottomLeft;
                }
            }
            else if (side == Flip.Vertical)
            {
                if (HorzDirection == 1 && VertDirection == 1)//-1
                {
                    p90 = bottomLeft;
                    p2 = bottomRight;
                    p3 = topLeft;
                }
                else if (HorzDirection == 1 && VertDirection == -1)//1
                {
                    p90 = topLeft;
                    p2 = topRight;
                    p3 = bottomLeft;
                }
                else if (HorzDirection == -1 && VertDirection == 1)//-1
                {
                    //since vertDirection has y flipped taken into account...
                    //p90 = topRight;vertDir is actually -1
                    //p2 = topLeft;
                    //p3 = bottomRight;
                    p90 = bottomRight;
                    p2 = bottomLeft;
                    p3 = topRight;
                }
                else if (HorzDirection == -1 && VertDirection == -1)//actually 1
                {
                    p90 = topRight;
                    p2 = topLeft;
                    p3 = bottomRight;
                }
            }
        }

        public void SetBounds(Rectangle bounds)
        {
            Origin = new Vector2(bounds.X, bounds.Y);

            // p90 and p2 are in the same column
            //p90 are tangent to p2 and p3
            //p2 and p3 connect thru hypotenuse
            List<Vector2> points = new List<Vector2>() { P1_90, P2, P3 };
            float bottom = Bottom;
            float right = Right;
            List<Vector2> bottomPoints = points.FindAll(p => p.Y == bottom);
            List<Vector2> rightPoints = points.FindAll(p => p.X == right);

            float deltaX = (float)bounds.Width - Width;
            float deltaY = (float)bounds.Height - Height;

            //move points

            foreach (Vector2 point in bottomPoints)
            {
                if (P1_90 == point)
                {
                    p90 = new Vector2(point.X, point.Y + deltaY) - Origin;
                }
                if (P2 == point)
                {
                    p2 = new Vector2(point.X, point.Y + deltaY) - Origin;
                }
                if (P3 == point)
                {
                    p3 = new Vector2(point.X, point.Y + deltaY) - Origin;
                }
            }
            foreach (Vector2 point in rightPoints)
            {
                if (P1_90 == point)
                {
                    p90 = new Vector2(point.X + deltaX, point.Y) - Origin;
                }
                if (P2 == point)
                {
                    p2 = new Vector2(point.X + deltaX, point.Y) - Origin;
                }
                if (P3 == point)
                {
                    p3 = new Vector2(point.X + deltaX, point.Y) - Origin;
                }
            }
        }
        public bool PointWithinTriangle(Vector2 p, bool notin)
        {
            if (p.X < Left ||
                p.X > Right ||
                p.Y < Bottom ||
                p.Y > Top)
                return false;

            //Origin = Origin;
            //P1_90 = P1_90;
            //P2 = P2;
            //P3 = P3;

            if (VertDirection == -1)
            {
                if (HorzDirection == 1)
                {
                    if (p.Y <= p.X * Slope + B)
                    {
                        return true;
                    }
                }
                else
                {
                    if (p.Y >= p.X * Slope + B)
                    {
                        return true;
                    }
                }
            }
            else
            {
                if (HorzDirection == 1)
                {
                    if (p.Y >= p.X * Slope + B)
                    {
                        return true;
                    }
                }
                else
                {
                    if (p.Y <= p.X * Slope + B)
                    {
                        return true;
                    }
                }
            }
            return false;
        }

        public Vector2 GetIntersectionDepth(Rectangle _rectB,  out bool intersecting)
        {
            intersecting = false;
          //make sure rects atleast intersect

            if (!Bounds.Intersects(_rectB))
            {
                return Vector2.Zero;
            }

            Vector2 topLeft = new Vector2(_rectB.Left, _rectB.Top);
            Vector2 topRight = new Vector2(_rectB.Right, _rectB.Top);
            Vector2 bottomLeft = new Vector2(_rectB.Left, _rectB.Bottom);
            Vector2 bottomRight = new Vector2(_rectB.Right, _rectB.Bottom);

            float left = Left;
            float right = Right;
            float top = Top;
            float bottom = Bottom;
            //left
            //upside down
            if (VertDirection == -1)
            {
                if (topLeft.X >= left &&
                    topLeft.X <= right &&
                    topLeft.Y >= top &&
                    topLeft.Y <= bottom)
                {
                    float y = topLeft.X * Slope + B;
                    if (topLeft.Y <= y)
                    {
                        intersecting = true;
                        return new Vector2(0, y - topLeft.Y);
                    }
                }
            }
            else
            {
                if (bottomLeft.X >= left &&
                   bottomLeft.X <= right &&
                   bottomLeft.Y >= top &&
                   bottomLeft.Y <= bottom)
                {
                    float y = bottomLeft.X * Slope + B;
                    if (bottomLeft.Y >= y)
                    {
                        intersecting = true;
                        return new Vector2(0, y - bottomLeft.Y);
                    }
                }
            }
            //  return 0;
            //test other side
            //right side
            //upside down
            if (VertDirection == -1)
            {
                //  if (HorzDirection = 1)
                //   {
                if (topRight.X >= left &&
                    topRight.X <= right &&
                    topRight.Y >= top &&
                   topRight.Y <= bottom)
                {
                    float y = topRight.X * Slope + B;
                    if (topRight.Y <= y)
                    {
                        intersecting = true;
                        return new Vector2(0, y - topRight.Y);
                    }
                }
            }
            else
            {
                if (bottomRight.X >= left &&
                   bottomRight.X <= right &&
                   bottomRight.Y >= top &&
                   bottomRight.Y <= bottom)
                {
                    float y = bottomRight.X * Slope + B;
                    if (bottomRight.Y >= y)
                    {
                        intersecting = true;
                        return new Vector2(0, y - bottomRight.Y);
                    }
                }
            }
            return Vector2.Zero;

        }

        public Vector2 GetPoint(float x)
        {
            //TODO: fix points when loaded, points should be the same as in the data
            //but when checking for slopes and stuff, use origin + the point
            x = MathHelper.Clamp(x, Left, Right);

            Vector2 point = new Vector2(x, x * Slope + B);


            return point;
        }


        public override string ToString()
        {
            return string.Format(
                "[Origin: {10}; Point_90: {0}; P2: {1}; P3: {2}; " +
                "Width: {3}; Height: {4}; HorizontalDirection: {5}; " +
                "VerticalDirection: {6}; Direction: {7}; B: {8}; Slope: {9}]",
                p90, p2, p3, Width, Height, HorzDirection, VertDirection, Direction, B, Slope, Origin);
        }
    }
}
